﻿using System;
using System.Xml.Serialization;
using Microsoft.Xna.Framework;

namespace Core.Graphics.Layers
{
    [XmlRoot("AutoTileLayer")]
    public class AutoTileLayer : TileLayer, IXmlSerializable
    {
        public AutoTileInfo AutoTileInfo { get; set; }
        public Point WorldCoordinate { get; set; }
        //The layer we draw from
        public TileLayer BaseAutoLayer { get; set; }

        public AutoTileLayer(AutoTileInfo AutoTileInfo)
        {
            this.AutoTileInfo = AutoTileInfo;
            BaseAutoLayer = new TileLayer(TileCollection.GetTilesForEmptyTileLayer(128, 128),128,128);
        }

        public AutoTileLayer() { /* XML Serialization */ }

        /// <summary>
        /// Set Tile at World Location in Layer
        /// </summary>
        /// <param name="tile"></param>
        /// <param name="worldloc"></param>
        public void SetBaseTileAtWorldLocation(Tile tile, Point worldloc)
        {
            //Convert location to local coordinate system
            int x = worldloc.X - WorldCoordinate.X;
            int y = worldloc.Y - WorldCoordinate.Y;
            //Set tile at location using base method
            BaseAutoLayer.SetTileAtLocation(tile, x, y);
            //After setting tile we need to update drawing layer
            UpdateDrawingLayer();
        }

        //Moves through tiles and figures out what tiles to put where
        public void UpdateDrawingLayer()
        {
            Tiles = TileCollection.GetTilesForEmptyTileLayer(128, 128);

            for (int y = 0; y < Height; y++)
            {
                for (int x = 0; x < Width; x++)
                {
                    Tile t = BaseAutoLayer.GetTileAtLocation(x, y);
                    
                    if (t.SpriteID != Tile.BlankTile.SpriteID)
                    {
                        //Set Drawing Layer Tile
                        SetTileAtLocation(t, x, y);
                    //Check 8 surrounding tiles to figure out what they should be.
                        //Check for 4 edges
                        bool Up = CheckUp(x, y);
                        bool Down = CheckDown(x, y);
                        bool Right = CheckRight(x, y);
                        bool Left = CheckLeft(x, y);
                        //Check for 4 corners
                        bool UpRight = CheckUpRight(x, y);
                        bool UpLeft = CheckUpLeft(x, y);
                        bool DownRight = CheckDownRight(x, y);
                        bool DownLeft = CheckDownLeft(x, y);

                        #region Edges
                        //UpEdge
                        if(!Up && !UpLeft && !UpRight)
                        {
                            SetTileAtLocation(AutoTileInfo.Up, x, y - 1);
                        }

                        //Bottom Edge
                        if (!Down && !DownLeft && !DownRight)
                        {
                            SetTileAtLocation(AutoTileInfo.Down, x, y + 1);
                        }

                        //Left Edge
                        if (!Left && !UpLeft && !DownLeft)
                        {
                            SetTileAtLocation(AutoTileInfo.Left, x - 1, y);
                        }

                        //Right Edge
                        if (!Right && !UpRight && !DownRight)
                        {
                            SetTileAtLocation(AutoTileInfo.Right, x + 1, y);
                        }
                        #endregion

                        #region OuterCorners
                        //UpRight Corner
                        if (!Up && !UpRight && !Right)
                        {
                            SetTileAtLocation(AutoTileInfo.UpRight, x + 1, y - 1);
                        }

                        //UpLeft Corner
                        if (!Up && !UpLeft && !Left)
                        {
                            SetTileAtLocation(AutoTileInfo.UpLeft, x - 1, y - 1);
                        }

                        //DownRight Corner
                        if (!Down && !DownRight && !Right)
                        {
                            SetTileAtLocation(AutoTileInfo.DownRight, x + 1, y + 1);
                        }

                        //DownLeft Corner
                        if (!Down && !DownLeft && !Left)
                        {
                            SetTileAtLocation(AutoTileInfo.DownLeft, x - 1, y + 1);
                        }

                        #endregion

                        #region InsideCorners
                        //UpRight
                        if (Up && Right && !UpRight)
                        {
                            SetTileAtLocation(AutoTileInfo.CornerUpRight, x + 1, y - 1);
                        }

                        //UpLeft
                        if (Up && Left && !UpLeft)
                        {
                            SetTileAtLocation(AutoTileInfo.CornerUpLeft, x - 1, y - 1);
                        }

                        //DownRight
                        if (Down && Right && !DownRight)
                        {
                            SetTileAtLocation(AutoTileInfo.CornerDownRight, x + 1, y + 1);
                        }

                        //DownLeft
                        if (Down && Left && !DownLeft)
                        {
                            SetTileAtLocation(AutoTileInfo.CornerDownLeft, x - 1, y + 1);
                        }
                        #endregion
                    }                    
                }
            }
        }

        #region TileChecks
        public bool CheckUp(int x, int y)
        {
            if (BaseAutoLayer.GetTileAtLocation(x, y-1).SpriteID != Tile.BlankTile.SpriteID)
                return true;

            return false;
        }

        public bool CheckDown(int x, int y)
        {
            if (BaseAutoLayer.GetTileAtLocation(x, y+1).SpriteID != Tile.BlankTile.SpriteID)
                return true;

            return false;
        }

        public bool CheckRight(int x, int y)
        {
            if (BaseAutoLayer.GetTileAtLocation(x+1, y).SpriteID != Tile.BlankTile.SpriteID)
                return true;

            return false;
        }

        public bool CheckLeft(int x, int y)
        {
            if (BaseAutoLayer.GetTileAtLocation(x-1, y).SpriteID != Tile.BlankTile.SpriteID)
                return true;

            return false;
        }

        public bool CheckUpRight(int x, int y)
        {
            if (BaseAutoLayer.GetTileAtLocation(x+1, y-1).SpriteID != Tile.BlankTile.SpriteID)
                return true;

            return false;
        }

        public bool CheckUpLeft(int x, int y)
        {
            if (BaseAutoLayer.GetTileAtLocation(x-1, y-1).SpriteID != Tile.BlankTile.SpriteID)
                return true;

            return false;
        }

        public bool CheckDownRight(int x, int y)
        {
            if (BaseAutoLayer.GetTileAtLocation(x+1, y+1).SpriteID != Tile.BlankTile.SpriteID)
                return true;

            return false;
        }

        public bool CheckDownLeft(int x, int y)
        {
            if (BaseAutoLayer.GetTileAtLocation(x-1, y+1).SpriteID != Tile.BlankTile.SpriteID)
                return true;

            return false;
        }
        #endregion

        #region IXmlSerializable Members

        System.Xml.Schema.XmlSchema IXmlSerializable.GetSchema()
        {
            return null;
        }

        void IXmlSerializable.ReadXml(System.Xml.XmlReader reader)
        {
            //Read base from XML
            base.ReadXml(reader);
            //Read in local properties
            AutoTileInfo = AutoTileInfoCollection.GlobalAutoTileSets.GetByName(
                reader.GetAttribute("AutoTileInfoName"));
            //Read World Coordinate of Auto Tile Layer
            WorldCoordinate = new Point(
                Convert.ToInt32(reader.GetAttribute("x")), Convert.ToInt32(reader.GetAttribute("y")));
        }

        void IXmlSerializable.WriteXml(System.Xml.XmlWriter writer)
        {
            //Write base to XML
            base.WriteXml(writer);
            //Write local properties to XML
            writer.WriteAttributeString("AutoTileInfoName", AutoTileInfo.Name);
            //Write World Coordinate of Auto Tile Layer
            writer.WriteAttributeString("x", WorldCoordinate.X.ToString());
            writer.WriteAttributeString("y", WorldCoordinate.Y.ToString());
        }

        #endregion
    }
}
